package utils;

import cn.hutool.core.lang.Assert;
import cn.smallbun.screw.core.Configuration;
import cn.smallbun.screw.core.engine.EngineConfig;
import cn.smallbun.screw.core.execute.DocumentationExecute;
import cn.smallbun.screw.core.process.ProcessConfig;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import config.DataSrc;
import config.Engine;
import config.ExportConfig;
import config.Process;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;

public class ExportUtil {

    private ExportUtil() {
    }

    public static ExportConfig getConfig() throws IOException {
        return getConfig("config.yaml");
    }

    /**
     * 读取yaml文件映射到实体类
     *
     * @param yamlFile yaml文件
     */
    public static ExportConfig getConfig(String yamlFile) throws IOException {

        Yaml yaml = new Yaml(new Constructor(ExportConfig.class));
        try (InputStream inputStream = ExportUtil.class.getClassLoader().getResourceAsStream(yamlFile)) {
            return yaml.load(inputStream);
        }

    }

    public static void exportDatabaseInfo() {
        // 获取配置
        ExportConfig exportConfig = null;
        try {
            exportConfig = getConfig();
        } catch (IOException e) {
            e.printStackTrace();
        }

        Assert.notNull(exportConfig, "yaml配置文件加载失败");

        //配置
        Configuration config = Configuration.builder()
                //版本
                .version(exportConfig.getVersion())
                //描述
                .description(exportConfig.getDescription())
                //数据源
                .dataSource(getDataSource(exportConfig.getDataSource()))
                //生成配置
                .engineConfig(getEngineConfig(exportConfig.getEngineConfig()))
                //生成配置
                .produceConfig(getProcessConfig(exportConfig.getProcessConfig()))
                .build();
        //执行生成
        new DocumentationExecute(config).execute();

    }

    /**
     * 获取datasource
     */
    private static DataSource getDataSource(DataSrc dataSrc) {
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setDriverClassName(dataSrc.getDriver());
        hikariConfig.setJdbcUrl(dataSrc.getUrl());
        hikariConfig.setUsername(dataSrc.getUsername());
        hikariConfig.setPassword(dataSrc.getPassword());
        // 设置可以获取tables remarks信息
        hikariConfig.addDataSourceProperty("useInformationSchema", "true");
        hikariConfig.setMinimumIdle(2);
        hikariConfig.setMaximumPoolSize(5);
        return new HikariDataSource(hikariConfig);
    }

    /**
     * 模板引擎配置
     */
    private static EngineConfig getEngineConfig(Engine engine) {
        //生成配置
        EngineConfig engineConfig = EngineConfig.builder()
                //生成文件路径
                .fileOutputDir(engine.getOutputDir())
                //打开目录
                .openOutputDir(engine.isOpenOutputDir())
                //文件类型
                .fileType(engine.getFileType())
                //生成模板实现
                .produceType(engine.getTemplateType())
                //自定义文件名称
                .fileName(engine.getFileName()).build();
        return engineConfig;
    }

    /**
     * 生成配置
     */
    private static ProcessConfig getProcessConfig(Process process) {
        ProcessConfig processConfig = ProcessConfig.builder()
                //指定生成逻辑、当存在指定表、指定表前缀、指定表后缀时，将生成指定表，其余表不生成、并跳过忽略表配置
                //根据名称指定表生成
                .designatedTableName(process.getDesignatedTableName())
                //根据表前缀生成
                .designatedTablePrefix(process.getDesignatedTablePrefix())
                //根据表后缀生成
                .designatedTableSuffix(process.getDesignatedTableSuffix())
                //忽略表名
                .ignoreTableName(process.getIgnoreTableName())
                //忽略表前缀
                .ignoreTablePrefix(process.getIgnorePrefix())
                //忽略表后缀
                .ignoreTableSuffix(process.getIgnoreSuffix())
                .build();
        return processConfig;
    }

}
